/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "backup/ReplicationBackupJob.h"
#include "client/ClientInvoke.h"
#include "utils/PluginUtilities.h"
#include "system/System.hpp"
#include "common/CleanMemPwd.h"

using namespace AppProtect;
using namespace nasreplicationservice;
using namespace Module;

namespace {
    constexpr auto MODULE = "ReplicationBackupJob";
    constexpr uint16_t SCAN_TIME_INTERVAL_SECEND = 5;
    constexpr int SCAN_RETRY_TIMES = 720; // 每隔5s扫描一次，超时时间1小时
    constexpr int RETRY_TIMES = 3;
    constexpr uint16_t SYNCHRONIZE_FINISHED = 97;
    constexpr float PROGRESS_OVERALL = 100.0;
    constexpr int32_t PROGRESS_HUNDRED = 100;
    constexpr int32_t PROGRESS_TEN = 10;
    constexpr int32_t PROGRESS_TWENTY = 20;
}

ReplicationBackupJob::ReplicationBackupJob()
{
}

int ReplicationBackupJob::CheckBackupJobType()
{
    SetJobToFinish();
    return MP_SUCCESS;
}

int ReplicationBackupJob::AllowBackupInLocalNode()
{
    if (!GetJobInfoBody()) {
        HCP_Log(ERR, MODULE) << "Get Job Info failed" << HCPENDLOG;
        return MP_FAILED;
    }
    if (!PluginUtils::CheckDeviceNetworkConnect(m_backupPara->protectEnv.endpoint)) {
        return MP_FAILED;
    }
    SetJobToFinish();
    return MP_SUCCESS;
}

int ReplicationBackupJob::PostJobInner()
{
    HCP_Log(INFO, MODULE) << "Start to execute post job, main task id is " << m_parentJobId
        << ", sub task id is" << m_subJobInfo->subJobId << HCPENDLOG;
    ActionResult result;
    SubJobDetails subJobDetails;
    LogDetail logDetail{};
    std::vector<LogDetail> logDetailList;
    if (!InitDeviceInfo()) {
        HCP_Log(ERR, MODULE) << "Init device info fail, main task id is " << m_parentJobId << HCPENDLOG;
        RemoveCertification(m_backupPara->protectEnv);
        AddLogDetail(logDetail, "nas_plugin_init_env_fail_label", JobLogLevel::TASK_LOG_ERROR);
        if (IsReportAgentErrorCode(logDetail)) {
            return MP_FAILED;
        }
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::FAILED);
        return MP_FAILED;
    }

    for (uint32_t i = 0; i < m_backupPara->repositories.size(); i++) {
        StorageRepository storage = m_backupPara->repositories[i];
        if (m_backupPara->repositories[i].repositoryType == RepositoryDataType::type::META_REPOSITORY) {
            m_metaRepo = std::make_shared<StorageRepository>(storage);
            if (m_metaRepo->path.size() != 0) {
                std::string cmd = "mkdir -p " + m_metaRepo->path[0] + "/" + m_parentJobId;
                std::vector<std::string> output;
                std::vector<std::string> errOutput;
                (void)Module::runShellCmdWithOutput(INFO, MODULE, 0, cmd, {}, output, errOutput);
            }
        }
    }

    if (m_jobResult == AppProtect::JobResult::type::SUCCESS) {
        if (!ReportCopyAdditionalInfo()) {
            RemoveCertification(m_backupPara->protectEnv);
            REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::FAILED);
            return MP_FAILED;
        }
    }

    CleanTask(m_jobResult);
    // 删除落盘的证书信息
    if (!RemoveCertification(m_backupPara->protectEnv)) {
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::FAILED);
        return MP_FAILED;
    }
    REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, PROGRESS_HUNDRED, 0, SubJobStatus::COMPLETED);
    HCP_Log(INFO, MODULE) << "Finish to execute post job, main task id is " << m_parentJobId << HCPENDLOG;
    return MP_SUCCESS;
}

bool ReplicationBackupJob::ReportCopyAdditionalInfo()
{
    ActionResult result;
    Copy image;
    image.__set_name(m_backupPara->copy.id); // 副本ID作为快照名称
    CopyExtendInfo copyExtendInfo;
    std::string extendInfo {};
    if (!JsonHelper::StructToJsonString(copyExtendInfo, extendInfo)) {
        HCP_Log(ERR, MODULE) << "copyExtendInfo transfer failed." << HCPENDLOG;
        return false;
    }
    image.__set_extendInfo(extendInfo);
    HCP_Log(INFO, MODULE) << "Report copy info" << WIPE_SENSITIVE(image.name) << HCPENDLOG;
    JobService::ReportCopyAdditionalInfo(result, m_parentJobId, image);
    return true;
}

bool ReplicationBackupJob::UpdateBasicDeviceInfo(ControlDeviceInfo &basicDeviceInfo)
{
    basicDeviceInfo.url = ""; // 使用安全IP登录，不需要IP和端口号
    basicDeviceInfo.compress = false;
    basicDeviceInfo.dedup = false;
    basicDeviceInfo.poolId = 0;
    for (int index = 0; index < m_backupPara->repositories.size(); index++) {
        StorageRepository storage = m_backupPara->repositories[index];
        if (storage.repositoryType == RepositoryDataType::type::DATA_REPOSITORY) {
            basicDeviceInfo.userName = storage.extendAuth.authkey;
            basicDeviceInfo.password = storage.extendAuth.authPwd;
            HCP_Log(INFO, MODULE) << "basicDeviceInfo.userName: "
                << WIPE_SENSITIVE(basicDeviceInfo.userName) << HCPENDLOG;

            std::vector<std::string> fsNameList;
            boost::split(fsNameList, storage.remotePath, boost::is_any_of("/"), boost::token_compress_off);
            if (fsNameList.size() <= 1) {
                HCP_Log(ERR, MODULE) << "Will cause out-of-bounds array" << HCPENDLOG;
                return false;
            }
            basicDeviceInfo.deviceName = fsNameList[1]; // DME创建的文件系统名称
            HCP_Log(INFO, MODULE) << "storage.remotePath " << WIPE_SENSITIVE(storage.remotePath) << HCPENDLOG;
            HCP_Log(INFO, MODULE) << "FileSystem Name " << WIPE_SENSITIVE(basicDeviceInfo.deviceName) << HCPENDLOG;
            std::vector<std::string> mgrIpList;
            boost::split(mgrIpList, storage.endpoint.ip, boost::is_any_of(","), boost::token_compress_off);
            basicDeviceInfo.port = "8088";
            std::string innerDoradoIp;
            if (GetContainerDoradoIp(innerDoradoIp) == MP_SUCCESS && (!innerDoradoIp.empty())) {
                mgrIpList.push_back(innerDoradoIp);
                HCP_Log(DEBUG, MODULE) << "Dorado ip in container is " << innerDoradoIp << HCPENDLOG;
            }
            HCP_Log(INFO, MODULE) << "storage Device IP List " << storage.endpoint.ip << HCPENDLOG;
            if (!UpdateDeviceAvilableIP(basicDeviceInfo, mgrIpList)) {
                return false;
            }
            return true;
        }
    }
    HCP_Log(INFO, MODULE) << "Update basicDeviceInfo fail, repo size: "
        << m_backupPara->repositories.size() << HCPENDLOG;
    return false;
}

bool ReplicationBackupJob::UpdateProductDeviceInfo(ControlDeviceInfo &productDeviceInfo)
{
    productDeviceInfo.userName = m_backupPara->protectEnv.auth.authkey;
    productDeviceInfo.password = m_backupPara->protectEnv.auth.authPwd;
    HCP_Log(INFO, MODULE) << "productDeviceInfo.userName: " << WIPE_SENSITIVE(productDeviceInfo.userName) << HCPENDLOG;
    productDeviceInfo.port = std::to_string(m_backupPara->protectEnv.port);
    productDeviceInfo.deviceName = m_backupPara->protectObject.name;

    HCP_Log(INFO, MODULE) << "Product device ip list " << m_backupPara->protectEnv.endpoint << HCPENDLOG;
    HCP_Log(INFO, MODULE) << "m_backupPara->protectEnv.extendInfo: " <<
        WIPE_SENSITIVE(m_backupPara->protectEnv.extendInfo) << HCPENDLOG;
    std::vector<std::string> productMgrIpList;
    if (!GetMgrIpFromExt(productMgrIpList, m_backupPara->protectEnv.extendInfo) ||
        !GetRepIpFromExt(m_backupPara->protectEnv.extendInfo)) {
        ERRLOG("GetMgrIpFromExt failed");
        return false;
    }

    if (!UpdateDeviceAvilableIP(productDeviceInfo, productMgrIpList)) {
        return false;
    }
    // 检查是否校验CA证书，并对证书落盘
    if (!CertVerifyMgr(m_backupPara->protectEnv, productDeviceInfo)) {
        return false;
    }
    return true;
}

bool ReplicationBackupJob::InitializeTask()
{
    HCP_Log(INFO, MODULE) << "Begin to initialize homo_dpa_task" << HCPENDLOG;
    SubJobDetails subJobDetails;
    LogDetail logDetail{};
    std::vector<LogDetail> logDetailList;
    ActionResult result;
    if (!InitDeviceInfo()) {
        HCP_Log(ERR, MODULE) << "Init device info fail" << HCPENDLOG;
        AddLogDetail(logDetail, "plugin_execute_prerequisit_task_fail_label", JobLogLevel::TASK_LOG_ERROR);
        if (IsReportAgentErrorCode(logDetail)) {
            return false;
        }
        AddErrCode(logDetail, HomoErrorCode::BACKUP_PARAMETER_CHECK_FAILED_ERROR_CODE); // 初始化环境参数失败
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::FAILED);
        return false;
    }
    m_nasReplicationServiceObj = NasRepServiceObjOp::NasReplicationService::GetReplicationInstance(
        m_productFSID, m_basicFSID, m_qos);
    m_nasReplicationServiceObj->SetTaskID(m_parentJobId);
    if (!m_selectedRepNameList.empty()) {
        std::vector<std::string> repPortNameList(m_selectedRepNameList.begin(), m_selectedRepNameList.end());
        m_nasReplicationServiceObj->SetProduckIscsiList(repPortNameList);
    }
    if ((m_localDeviceController->GetESN(m_productEsn) != MP_SUCCESS) ||
        (m_remoteDeviceController->GetESN(m_basicEsn) != MP_SUCCESS)) {
        ERRLOG("Get ESN failed!");
        AddLogDetail(logDetail, "plugin_execute_prerequisit_task_fail_label", JobLogLevel::TASK_LOG_ERROR,
            m_productEsn, m_productFSID, m_basicFSID);
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::FAILED);
        return false;
    }
    bool isPrimary = true;
    m_localDeviceController->GetReplicationPairWithFsId(m_productFSID, m_basicEsn, isPrimary);
    if (!isPrimary) {
        ERRLOG("fsid in product is secondary end for existing replication pair!");
        AddLogDetail(logDetail, "nas_plugin_pair_secondary_end_fail_label", JobLogLevel::TASK_LOG_ERROR);
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::FAILED);
        return false;
    }
    if (!PrepareRemoteReplicatonPair()) {
        return false;
    }
    if (!CreateSnapShotInStorage()) {
        return false;
    }
    AddLogDetail(logDetail, "", JobLogLevel::TASK_LOG_INFO, m_productEsn, m_productFSID, m_basicFSID);
    REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
    HCP_Log(INFO, MODULE) << "Initialize homo_dpa_task success" << HCPENDLOG;
    return true;
}

bool ReplicationBackupJob::PrepareRemoteReplicatonPair()
{
    SubJobDetails subJobDetails;
    LogDetail logDetail{};
    std::vector<LogDetail> logDetailList;
    ActionResult result;
    auto ret = m_nasReplicationServiceObj->
        PrepareRemoteReplicatonPair(m_remoteDeviceController, m_localDeviceController);
    if (ret != NasRepServiceObjOp::NasReplicationServiceErrorCode::ReplicationServiceNormal) {
        if (ret == NasRepServiceObjOp::NasReplicationServiceErrorCode::ReplicationDeviceFault) {
            AddLogDetail(logDetail, "plugin_remote_device_failure_label", JobLogLevel::TASK_LOG_ERROR,
                m_productEsn, m_productFSID, m_basicFSID);
            REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
        }
        AddLogDetail(logDetail, "plugin_execute_prerequisit_task_fail_label", JobLogLevel::TASK_LOG_ERROR,
            m_productEsn, m_productFSID, m_basicFSID);
        if (IsReportAgentErrorCode(logDetail)) {
            return false;
        }
        int64_t errorCode = (m_localDeviceController->GetErrorCode() != MP_SUCCESS)
            ? m_localDeviceController->GetErrorCode() : m_remoteDeviceController->GetErrorCode();
        AddErrCode(logDetail, errorCode);
        HCP_Log(ERR, MODULE) << "Prepare remotereplicatonpair fail, err: " << errorCode << HCPENDLOG;
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::FAILED);
        return false;
    }
    return true;
}

bool ReplicationBackupJob::InitDeviceInfo()
{
    ControlDeviceInfo basicDeviceInfo;
    ControlDeviceInfo productDeviceInfo;
    DeviceDetails info;
    HCP_Log(INFO, MODULE) << "Enter InitDeviceInfo" << HCPENDLOG;
    if (!GetJobInfoBody()) {
        HCP_Log(ERR, MODULE) << "Get Job Info failed" << HCPENDLOG;
        return false;
    }
    if (m_qos <= 0) {
        m_qos = 1024; // 未配置Qos策略，默认按1024M执行
    }
    ApplicationEnvExtent applicationEnvExtentInfo {};
    if (!JsonHelper::JsonStringToStruct(m_backupPara->protectEnv.extendInfo, applicationEnvExtentInfo)) {
        HCP_Log(ERR, MODULE) << "ApplicationEnvExtentInfo is invaild." << HCPENDLOG;
    }
    if (std::stoi(applicationEnvExtentInfo.verifyStatus) == MP_TRUE) {
        if (callCheckCertThumbPrint(m_backupPara->protectEnv) != MP_SUCCESS) {
            HCP_Log(ERR, MODULE) << "CheckCert thumbprint failed" << HCPENDLOG;
            return false;
        }
    }
    if (!UpdateBasicDeviceInfo(basicDeviceInfo)) {
        return false;
    }
    m_remoteDeviceController = std::make_unique<DoradoNas>(basicDeviceInfo, false);
    m_remoteDeviceController->QueryFileSystem(info);
    m_basicFSID = m_remoteDeviceController->GetFileSystemId();
    if (!UpdateProductDeviceInfo(productDeviceInfo)) {
        return false;
    }
    ReplicationProtectObjectExtendInfo extendInfo {};
    if (!JsonHelper::JsonStringToStruct(m_backupPara->protectObject.extendInfo, extendInfo)) {
        HCP_Log(ERR, MODULE) << "ReplicationProtectObjectExtendInfo is invaild." << HCPENDLOG;
        return false;
    }
    m_productFSID = extendInfo.fileSystemId;
    m_localDeviceController = std::make_unique<DoradoNas>(productDeviceInfo, m_productFSID, false);
    m_localDeviceController->SetRetryAttr(RETRY_TIMES);  // 设置重试次数(3次)，间隔默认10秒
    HCP_Log(INFO, MODULE) << "Genrate m_localDeviceController successfully" << HCPENDLOG;
    m_isBackUpFlow = true; // 备份
    return true;
}

int ReplicationBackupJob::callCheckCertThumbPrint(const AppProtect::ApplicationEnvironment& protectEnv)
{
    EnvAuthExtendInfo authExtendInfo {};
    if (!JsonHelper::JsonStringToStruct(protectEnv.auth.extendInfo, authExtendInfo)) {
        HCP_Log(ERR, MODULE) << "NasAuthExtendInfo is invaild." << HCPENDLOG;
    }
    const std::string thumbPrint = authExtendInfo.fingerPrint;
    const std::string endpoint = protectEnv.endpoint;
    const int32_t port = protectEnv.port;
    HCP_Log(INFO, MODULE) << "CheckCertThumbprint param"
        << ", endpoint: " << endpoint
        << ", port: " << port
        << ", thumbprint: " << WIPE_SENSITIVE(thumbPrint) << HCPENDLOG;
    ActionResult ret;
    SecurityService::CheckCertThumbPrint(ret, endpoint, port, thumbPrint);
    if (ret.code != MP_SUCCESS) {
        HCP_Log(ERR, MODULE) << "CheckCertThumbprint"
        << ", endpoint: " << endpoint
        << ", port: " << port
        << ", thumbprint: " << WIPE_SENSITIVE(thumbPrint) << HCPENDLOG;
        return MP_FAILED;
    }
    return MP_SUCCESS;
}

bool ReplicationBackupJob::CheckAndCreatePair()
{
    SubJobDetails subJobDetails;
    LogDetail logDetail{};
    std::vector<LogDetail> logDetailList;
    ActionResult result;
    if (m_nasReplicationServiceObj->IsExistPairValid()) {
        AddLogDetail(logDetail, "", JobLogLevel::TASK_LOG_INFO);
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
        return true;
    }
    HCP_Log(INFO, MODULE) << "Pair " << m_pairID << " is invalid, Create a new pair" << HCPENDLOG;
    int remoteResId = std::atoi(m_basicFSID.c_str());
    int localResId = std::atoi(m_productFSID.c_str());
    std::string remoteDevId = m_nasReplicationServiceObj->m_remoteDeviceID;
    std::string pairID;
    ReplicationPairInfo replicationPairInfo;
    if (m_nasReplicationServiceObj->GetPairInfoInProduct(m_localDeviceController, m_remoteDeviceController, pairID)) {
        if (m_nasReplicationServiceObj->GetPairInfoByID(m_remoteDeviceController, pairID, replicationPairInfo)) {
            if (replicationPairInfo.status == INVALIID) {
                // 无效删除pair
                HCP_Log(WARN, MODULE) << "Pair " << pairID  << " is invalid. Delete Pair." << HCPENDLOG;
                m_nasReplicationServiceObj->DeleteReplicatonPair(m_remoteDeviceController, m_pairID);
            }
        }
    }
    if (!m_nasReplicationServiceObj->CreateReplicationPair(m_localDeviceController, localResId,
        remoteDevId, remoteResId, m_pairID)) {
        HCP_Log(ERR, MODULE) << "Create a new pair fail" << HCPENDLOG;
        AddLogDetail(logDetail, "plugin_execute_prerequisit_task_fail_label", JobLogLevel::TASK_LOG_ERROR);
        if (IsReportAgentErrorCode(logDetail)) {
            return false;
        }
        AddErrCode(logDetail, m_localDeviceController->GetErrorCode());
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0,
            SubJobStatus::FAILED);
        return false;
    }
    AddLogDetail(logDetail, "", JobLogLevel::TASK_LOG_INFO);
    REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0,
        SubJobStatus::RUNNING);
    HCP_Log(INFO, MODULE) << "Create a new pair " << m_pairID << HCPENDLOG;
    return true;
}

bool ReplicationBackupJob::PreStartTask()
{
    SubJobDetails subJobDetails;
    LogDetail logDetail{};
    std::vector<LogDetail> logDetailList;
    ActionResult result;
    if (!InitDeviceInfo()) {
        HCP_Log(ERR, MODULE) << "Init device info fail" << HCPENDLOG;
        AddLogDetail(logDetail, "nas_plugin_backup_failed_label", JobLogLevel::TASK_LOG_ERROR);
        if (IsReportAgentErrorCode(logDetail)) {
            return false;
        }
        AddErrCode(logDetail, HomoErrorCode::BACKUP_PARAMETER_CHECK_FAILED_ERROR_CODE); // 初始化环境参数失败
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, m_curProcess, 0, SubJobStatus::FAILED);
        return false;
    }

    if (!GetRemoteFileSystemInfo()) {
        AddLogDetail(logDetail, "nas_plugin_backup_failed_label", JobLogLevel::TASK_LOG_ERROR);
        if (IsReportAgentErrorCode(logDetail)) {
            return false;
        }
        AddErrCode(logDetail, HomoErrorCode::BACKUP_PARAMETER_CHECK_FAILED_ERROR_CODE); // 初始化环境参数失败
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, m_curProcess, 0, SubJobStatus::FAILED);
        return false;
    }

    m_nasReplicationServiceObj = NasRepServiceObjOp::NasReplicationService::GetReplicationInstance(
        m_productFSID, m_basicFSID, m_qos);
    m_nasReplicationServiceObj->SetTaskID(m_parentJobId);

    if (!m_nasReplicationServiceObj->GetPairInfoInProduct(
        m_localDeviceController, m_remoteDeviceController, m_pairID)) {
        AddLogDetail(logDetail, "nas_plugin_backup_failed_label", JobLogLevel::TASK_LOG_ERROR);
        if (IsReportAgentErrorCode(logDetail)) {
            return false;
        }
        int64_t errorCode = m_localDeviceController->GetErrorCode();
        // 如果errorCode为0，表示m_localDeviceController的请求未出现错误
        errorCode = (errorCode ==  MP_SUCCESS) ? HomoErrorCode::REPLICATION_PAIR_NOTEXIST_ERROR_CODE : errorCode;
        AddErrCode(logDetail, HomoErrorCode::REPLICATION_PAIR_NOTEXIST_ERROR_CODE); // 复制pair不存在
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, m_curProcess, 0, SubJobStatus::FAILED);
        return false;
    }

    return true;
}

bool ReplicationBackupJob::GetRemoteFileSystemInfo()
{
    DeviceDetails info;
    if (m_remoteDeviceController->Query(info) != MP_SUCCESS) {
        ERRLOG("Get filesystem info failed!");
        return false;
    }
    HCP_Log(DEBUG, MODULE) << "Current filesystem used capacity before sync is " << info.usedCapacity
        << ", id:" << info.deviceId << ", name:" << WIPE_SENSITIVE(info.deviceName) << HCPENDLOG;
    m_usedCapacity = info.usedCapacity;
    m_isReportData = true; // 备份流程，需要上报数据量
    std::vector<std::string> fileContent { std::to_string(m_usedCapacity) };
    INFOLOG("capacityPath: %s", m_capacityPath.c_str());
    if (!PluginUtils::IsFileExist(m_capacityPath) &&
        !PluginUtils::WriteFile(m_capacityPath, fileContent)) {
        ERRLOG("Write filesytem capacity failed.");
        return false;
    }
    return true;
}

bool ReplicationBackupJob::CreateSnapShotInStorage()
{
    SubJobDetails subJobDetails;
    LogDetail logDetail{};
    std::vector<LogDetail> logDetailList;
    ActionResult result;
    DeviceDetails info;
    m_localDeviceController->QueryFileSystem(info);
    std::string fileSystemId = std::to_string(info.deviceId);
    std::string productEsn;
    m_localDeviceController->GetESN(productEsn);
    m_productEsn = productEsn;
    AddLogDetail(logDetail, "nas_plugin_create_snapshot_label", JobLogLevel::TASK_LOG_INFO, productEsn, fileSystemId);
    REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, m_curProcess, 0, SubJobStatus::RUNNING);
    // 备份任务：先打快照，并将快照信息保存到副本中
    m_snapshotName = m_backupPara->copy.id;
    if (m_snapshotName.empty()) {
        HCP_Log(ERR, MODULE) << "Get snapshot " << m_snapshotName << " failed" << HCPENDLOG;
        AddLogDetail(logDetail, "plugin_create_snapshot_fail_label", JobLogLevel::TASK_LOG_ERROR, m_snapshotName);
        if (IsReportAgentErrorCode(logDetail)) {
            return false;
        }
        AddErrCode(logDetail, HomoErrorCode::SNAPSHOT_NAME_RANGE_INVAILED_ERROR_CODE); // 快照名称长度是1和32之间
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, m_curProcess, 0, SubJobStatus::FAILED);
        return false;
    }
    HCP_Log(INFO, MODULE) << "Get snapshot " << m_snapshotName << HCPENDLOG;
    std::string snapShotId;
    if (!m_nasReplicationServiceObj->CreateSnapShotInStorage(m_localDeviceController, m_snapshotName, snapShotId)) {
        HCP_Log(ERR, MODULE) << "Create snapshot " << m_snapshotName << " fail" << HCPENDLOG;
        AddLogDetail(logDetail, "plugin_create_snapshot_fail_label", JobLogLevel::TASK_LOG_ERROR, m_snapshotName);
        if (IsReportAgentErrorCode(logDetail)) {
            return false;
        }
        AddErrCode(logDetail, m_localDeviceController->GetErrorCode());
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, m_curProcess, 0, SubJobStatus::FAILED);
        return false;
    }
    HCP_Log(INFO, MODULE) << "Create snapshot in productstorage success. snapshotname: " << m_snapshotName << HCPENDLOG;
    return true;
}

void ReplicationBackupJob::CleanTask(AppProtect::JobResult::type status)
{
    ActionResult result;
    SubJobDetails subJobDetails;
    LogDetail logDetail{};
    std::vector<LogDetail> logDetailList;
    HCP_Log(INFO, MODULE) << "Start clean task..." << HCPENDLOG;
    m_nasReplicationServiceObj = NasRepServiceObjOp::NasReplicationService::GetReplicationInstance(
        m_productFSID, m_basicFSID, m_qos);
    m_nasReplicationServiceObj->SetTaskID(m_parentJobId);

    if (!m_nasReplicationServiceObj->GetPairInfoInProduct(
        m_localDeviceController, m_remoteDeviceController, m_pairID)) {
        HCP_Log(ERR, MODULE) << "Get pair infomation failed when cleaning task." << HCPENDLOG;
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
        return;
    }
    // 公共：pair分裂，并进行主从切换
    REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
    if (!m_nasReplicationServiceObj->SplitReplicationPair(m_localDeviceController, m_pairID)) {
        HCP_Log(ERR, MODULE) << "Failed to split replication pair when cleaning task." << m_pairID << HCPENDLOG;
    }

    // pair创建完毕后，在本端检查当前pair主从关系是否满足要求，如果不满足则需要进行主从切换处理
    ReplicationPairInfo replicationPairInfo;
    if (m_nasReplicationServiceObj->GetPairInfoByID(m_localDeviceController, m_pairID, replicationPairInfo)) {
        if (!replicationPairInfo.isPrimary) {
            REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
            if (!SwitchOverPrimaryAndSecondResource(m_localDeviceController, m_pairID)) {
                HCP_Log(ERR, MODULE) << "Failed to switch overPrimaryAndSecondResource fail " << m_pairID << HCPENDLOG;
                REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
            }
        }
    }
    DeleteBackupSnapshot(status);
    return;
}

void ReplicationBackupJob::DeleteBackupSnapshot(AppProtect::JobResult::type status)
{
    ActionResult result;
    SubJobDetails subJobDetails;
    LogDetail logDetail{};
    std::vector<LogDetail> logDetailList;
    std::string snapshotname = m_backupPara->copy.id;
    AddLogDetail(logDetail, "", JobLogLevel::TASK_LOG_INFO, snapshotname);
    REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
    if (snapshotname.empty()) {
        HCP_Log(ERR, MODULE) << "Get snapshot[ " << (snapshotname) << "] failed" << HCPENDLOG;
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
        return;
    }
    // 删除生产端快照
    if (!m_nasReplicationServiceObj->DeleteSnapShotInStorage(m_localDeviceController, snapshotname)) {
        HCP_Log(ERR, MODULE) << "Delete snapshot in product storage fail, snapshotname "
            << (snapshotname) << HCPENDLOG;
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
    }
    HCP_Log(INFO, MODULE) << "Delete snapshot in product Storage success" << HCPENDLOG;
    // 删除本端快照
    REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
    if (!m_nasReplicationServiceObj->DeleteSnapShotInStorage(m_remoteDeviceController, snapshotname)) {
        HCP_Log(ERR, MODULE) << "Delete snapshot in localstorage fail, snapshotID "
            << (snapshotname) << HCPENDLOG;
        REPORT_LOG2AGENT(subJobDetails, result, logDetailList, logDetail, 0, 0, SubJobStatus::RUNNING);
    }
    return;
}

bool ReplicationBackupJob::GetJobInfoBody()
{
    if (m_jobCommonInfo == nullptr) {
        HCP_Log(ERR, MODULE) << "jobCommonInfo is null" << HCPENDLOG;
        return false;
    }
    m_backupPara = std::dynamic_pointer_cast<AppProtect::BackupJob>(GetJobInfo()->GetJobInfo());
    m_qos = m_backupPara->jobParam.qos.bandwidth;
    /* 获取cache挂载路径，用于存数据量，计算备份前后文件系统的数据量差异 */
    for (const StorageRepository& repo : m_backupPara->repositories) {
        if (repo.repositoryType == RepositoryDataType::type::CACHE_REPOSITORY) {
            if (repo.path.empty()) {
                ERRLOG("Cache repo path is empty!");
                return false;
            }
            m_capacityPath = repo.path[0] + "/filesystem_capacity";
            DBGLOG("Init capacity path: %s", m_capacityPath.c_str());
            break;
        }
    }
    return true;
}
